3 class ResourceLoaderStartUpModuleTest
extends ResourceLoaderTestCase
{
5 protected static function expandPlaceholders( $text ) {
7 '{blankVer}' => self
::BLANK_VERSION
11 public function provideGetModuleRegistrations() {
14 'msg' => 'Empty registry',
17 mw.loader.addSource( {
18 "local": "/w/load.php"
20 mw.loader.register( [] );'
23 'msg' => 'Basic registry',
25 'test.blank' => new ResourceLoaderTestModule(),
28 mw.loader.addSource( {
29 "local": "/w/load.php"
39 'msg' => 'Optimise the dependency tree (basic case)',
41 'a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'b', 'c', 'd' ] ] ),
42 'b' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'c' ] ] ),
43 'c' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
44 'd' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
47 mw.loader.addSource( {
48 "local": "/w/load.php"
77 'msg' => 'Optimise the dependency tree (tolerate unknown deps)',
79 'a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'b', 'c', 'x' ] ] ),
80 'b' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'c', 'x' ] ] ),
81 'c' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
84 mw.loader.addSource( {
85 "local": "/w/load.php"
111 // Regression test for T223402.
112 'msg' => 'Optimise the dependency tree (indirect circular dependency)',
114 'top' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'middle1', 'util' ] ] ),
115 'middle1' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'middle2', 'util' ] ] ),
116 'middle2' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'bottom' ] ] ),
117 'bottom' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'top' ] ] ),
118 'util' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
121 mw.loader.addSource( {
122 "local": "/w/load.php"
124 mw.loader.register( [
162 // Regression test for T223402.
163 'msg' => 'Optimise the dependency tree (direct circular dependency)',
165 'top' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'util', 'top' ] ] ),
166 'util' => new ResourceLoaderTestModule( [ 'dependencies' => [] ] ),
169 mw.loader.addSource( {
170 "local": "/w/load.php"
172 mw.loader.register( [
188 'msg' => 'Version falls back gracefully if getVersionHash throws',
191 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
192 ->setMethods( [ 'getVersionHash' ] )->getMock() )
193 && $mock->method( 'getVersionHash' )->will(
194 $this->throwException( new Exception
)
199 mw.loader.addSource( {
200 "local": "/w/load.php"
202 mw.loader.register( [
213 'msg' => 'Use version from getVersionHash',
216 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
217 ->setMethods( [ 'getVersionHash' ] )->getMock() )
218 && $mock->method( 'getVersionHash' )->willReturn( '1234567' )
222 mw.loader.addSource( {
223 "local": "/w/load.php"
225 mw.loader.register( [
233 'msg' => 'Re-hash version from getVersionHash if too long',
236 ( $mock = $this->getMockBuilder( ResourceLoaderTestModule
::class )
237 ->setMethods( [ 'getVersionHash' ] )->getMock() )
238 && $mock->method( 'getVersionHash' )->willReturn( '12345678' )
242 mw.loader.addSource( {
243 "local": "/w/load.php"
245 mw.loader.register( [
253 'msg' => 'Group signature',
255 'test.blank' => new ResourceLoaderTestModule(),
256 'test.group.foo' => new ResourceLoaderTestModule( [ 'group' => 'x-foo' ] ),
257 'test.group.bar' => new ResourceLoaderTestModule( [ 'group' => 'x-bar' ] ),
260 mw.loader.addSource( {
261 "local": "/w/load.php"
263 mw.loader.register( [
283 'msg' => 'Different target (non-test should not be registered)',
285 'test.blank' => new ResourceLoaderTestModule(),
286 'test.target.foo' => new ResourceLoaderTestModule( [ 'targets' => [ 'x-foo' ] ] ),
289 mw.loader.addSource( {
290 "local": "/w/load.php"
292 mw.loader.register( [
300 'msg' => 'Safemode disabled (default; register all modules)',
302 // Default origin: ORIGIN_CORE_SITEWIDE
303 'test.blank' => new ResourceLoaderTestModule(),
304 'test.core-generated' => new ResourceLoaderTestModule( [
305 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
307 'test.sitewide' => new ResourceLoaderTestModule( [
308 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
310 'test.user' => new ResourceLoaderTestModule( [
311 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
315 mw.loader.addSource( {
316 "local": "/w/load.php"
318 mw.loader.register( [
324 "test.core-generated",
338 'msg' => 'Safemode enabled (filter modules with user/site origin)',
339 'extraQuery' => [ 'safemode' => '1' ],
341 // Default origin: ORIGIN_CORE_SITEWIDE
342 'test.blank' => new ResourceLoaderTestModule(),
343 'test.core-generated' => new ResourceLoaderTestModule( [
344 'origin' => ResourceLoaderModule
::ORIGIN_CORE_INDIVIDUAL
346 'test.sitewide' => new ResourceLoaderTestModule( [
347 'origin' => ResourceLoaderModule
::ORIGIN_USER_SITEWIDE
349 'test.user' => new ResourceLoaderTestModule( [
350 'origin' => ResourceLoaderModule
::ORIGIN_USER_INDIVIDUAL
354 mw.loader.addSource( {
355 "local": "/w/load.php"
357 mw.loader.register( [
363 "test.core-generated",
369 'msg' => 'Foreign source',
372 'loadScript' => 'http://example.org/w/load.php',
373 'apiScript' => 'http://example.org/w/api.php',
377 'test.blank' => new ResourceLoaderTestModule( [ 'source' => 'example' ] ),
380 mw.loader.addSource( {
381 "local": "/w/load.php",
382 "example": "http://example.org/w/load.php"
384 mw.loader.register( [
395 'msg' => 'Conditional dependency function',
397 'test.x.core' => new ResourceLoaderTestModule(),
398 'test.x.polyfill' => new ResourceLoaderTestModule( [
399 'skipFunction' => 'return true;'
401 'test.y.polyfill' => new ResourceLoaderTestModule( [
409 'test.z.foo' => new ResourceLoaderTestModule( [
418 mw.loader.addSource( {
419 "local": "/w/load.php"
421 mw.loader.register( [
440 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
454 // This may seem like an edge case, but a plain MediaWiki core install
455 // with a few extensions installed is likely far more complex than this
456 // even, not to mention an install like Wikipedia.
457 // TODO: Make this even more realistic.
458 'msg' => 'Advanced (everything combined)',
461 'loadScript' => 'http://example.org/w/load.php',
462 'apiScript' => 'http://example.org/w/api.php',
466 'test.blank' => new ResourceLoaderTestModule(),
467 'test.x.core' => new ResourceLoaderTestModule(),
468 'test.x.util' => new ResourceLoaderTestModule( [
473 'test.x.foo' => new ResourceLoaderTestModule( [
478 'test.x.bar' => new ResourceLoaderTestModule( [
484 'test.x.quux' => new ResourceLoaderTestModule( [
492 'test.group.foo.1' => new ResourceLoaderTestModule( [
495 'test.group.foo.2' => new ResourceLoaderTestModule( [
498 'test.group.bar.1' => new ResourceLoaderTestModule( [
501 'test.group.bar.2' => new ResourceLoaderTestModule( [
503 'source' => 'example',
505 'test.target.foo' => new ResourceLoaderTestModule( [
506 'targets' => [ 'x-foo' ],
508 'test.target.bar' => new ResourceLoaderTestModule( [
509 'source' => 'example',
510 'targets' => [ 'x-foo' ],
514 mw.loader.addSource( {
515 "local": "/w/load.php",
516 "example": "http://example.org/w/load.php"
518 mw.loader.register( [
588 * @dataProvider provideGetModuleRegistrations
589 * @covers ResourceLoaderStartUpModule
590 * @covers ResourceLoader::makeLoaderRegisterScript
592 public function testGetModuleRegistrations( $case ) {
593 $extraQuery = $case['extraQuery'] ??
[];
594 $context = $this->getResourceLoaderContext( $extraQuery );
595 $rl = $context->getResourceLoader();
596 if ( isset( $case['sources'] ) ) {
597 $rl->addSource( $case['sources'] );
599 $rl->register( $case['modules'] );
600 $module = new ResourceLoaderStartUpModule();
601 $out = ltrim( $case['out'], "\n" );
603 // Disable log from getModuleRegistrations via MWExceptionHandler
604 // for case where getVersionHash() is expected to throw.
605 $this->setLogger( 'exception', new Psr\Log\
NullLogger() );
608 self
::expandPlaceholders( $out ),
609 $module->getModuleRegistrations( $context ),
614 public static function provideRegistrations() {
617 'test.blank' => new ResourceLoaderTestModule(),
618 'test.min' => new ResourceLoaderTestModule( [
634 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
635 * @dataProvider provideRegistrations
637 public function testRegistrationsMinified( $modules ) {
638 $this->setMwGlobals( 'wgResourceLoaderDebug', false );
640 $context = $this->getResourceLoaderContext();
641 $rl = $context->getResourceLoader();
642 $rl->register( $modules );
643 $module = new ResourceLoaderStartUpModule();
644 $out = 'mw.loader.addSource({"local":"/w/load.php"});' . "\n"
645 . 'mw.loader.register(['
646 . '["test.blank","{blankVer}"],'
647 . '["test.min","{blankVer}",[0],null,null,'
648 . '"return!!(window.JSON\u0026\u0026JSON.parse\u0026\u0026JSON.stringify);"'
652 self
::expandPlaceholders( $out ),
653 $module->getModuleRegistrations( $context ),
659 * @covers ResourceLoaderStartUpModule::getModuleRegistrations
660 * @dataProvider provideRegistrations
662 public function testRegistrationsUnminified( $modules ) {
663 $context = $this->getResourceLoaderContext();
664 $rl = $context->getResourceLoader();
665 $rl->register( $modules );
666 $module = new ResourceLoaderStartUpModule();
668 'mw.loader.addSource( {
669 "local": "/w/load.php"
671 mw.loader.register( [
684 "return !!( window.JSON \u0026\u0026 JSON.parse \u0026\u0026 JSON.stringify);"
689 self
::expandPlaceholders( $out ),
690 $module->getModuleRegistrations( $context ),
696 * @covers ResourceLoaderStartupModule::getDefinitionSummary
698 public function testGetVersionHash_varyConfig() {
699 $context = $this->getResourceLoaderContext();
701 $this->setMwGlobals( 'wgArticlePath', '/w1' );
702 $module = new ResourceLoaderStartupModule();
703 $version1 = $module->getVersionHash( $context );
704 $module = new ResourceLoaderStartupModule();
705 $version2 = $module->getVersionHash( $context );
707 $this->setMwGlobals( 'wgArticlePath', '/w3' );
708 $module = new ResourceLoaderStartupModule();
709 $version3 = $module->getVersionHash( $context );
714 'Deterministic version hash'
717 $this->assertNotEquals(
720 'Config change impacts version hash'
725 * @covers ResourceLoaderStartupModule
727 public function testGetVersionHash_varyModule() {
728 $context1 = $this->getResourceLoaderContext();
729 $rl1 = $context1->getResourceLoader();
731 'test.a' => new ResourceLoaderTestModule(),
732 'test.b' => new ResourceLoaderTestModule(),
734 $module = new ResourceLoaderStartupModule();
735 $version1 = $module->getVersionHash( $context1 );
737 $context2 = $this->getResourceLoaderContext();
738 $rl2 = $context2->getResourceLoader();
740 'test.b' => new ResourceLoaderTestModule(),
741 'test.c' => new ResourceLoaderTestModule(),
743 $module = new ResourceLoaderStartupModule();
744 $version2 = $module->getVersionHash( $context2 );
746 $context3 = $this->getResourceLoaderContext();
747 $rl3 = $context3->getResourceLoader();
749 'test.a' => new ResourceLoaderTestModule(),
750 'test.b' => new ResourceLoaderTestModule( [ 'script' => 'different' ] ),
752 $module = new ResourceLoaderStartupModule();
753 $version3 = $module->getVersionHash( $context3 );
755 // Module name *is* significant (T201686)
756 $this->assertNotEquals(
759 'Module name is significant'
762 $this->assertNotEquals(
765 'Hash change of any module impacts startup hash'
770 * @covers ResourceLoaderStartupModule
772 public function testGetVersionHash_varyDeps() {
773 $context = $this->getResourceLoaderContext();
774 $rl = $context->getResourceLoader();
776 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'y' ] ] ),
778 $module = new ResourceLoaderStartupModule();
779 $version1 = $module->getVersionHash( $context );
781 $context = $this->getResourceLoaderContext();
782 $rl = $context->getResourceLoader();
784 'test.a' => new ResourceLoaderTestModule( [ 'dependencies' => [ 'x', 'z' ] ] ),
786 $module = new ResourceLoaderStartupModule();
787 $version2 = $module->getVersionHash( $context );
789 // Dependencies *are* significant (T201686)
790 $this->assertNotEquals(
793 'Dependencies are significant'